import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy import stats
import matplotlib

# Reset to default font configuration
matplotlib.rcParams.update(matplotlib.rcParamsDefault)

def analyze_matrix_specific_cache():
    # Read CSV files
    try:
        df_results = pd.read_csv('cache_results.csv')
        df_details = pd.read_csv('cache_access_details.csv')
        print("Data loaded successfully!")
        print(f"Summary data shape: {df_results.shape}")
        print(f"Detail data shape: {df_details.shape}")
        
    except FileNotFoundError:
        print("CSV files not found, please run Java program to generate data first")
        return
    
    # Data preprocessing
    print("\nStatistics by matrix type:")
    print(df_results.groupby('matrix_type').agg({
        'hit_rate': ['mean', 'std', 'min', 'max'],
        'miss_rate': ['mean', 'std'],
        'spatial_locality': ['mean', 'std']
    }))

    df_details = df_details.groupby(['experiment_name','matrix_type'], group_keys=False).apply(
        lambda x: x.iloc[:max(1, int(len(x) * 0.0001))]
    ).reset_index(drop=True)
    print("\n已筛选每个 experiment_name,matrix_type 前 0.01% 的详细访问数据")
    
    # Create analysis charts
    create_matrix_specific_plots(df_results, df_details)
    
    # Generate detailed analysis report
    # generate_detailed_analysis(df_results, df_details)
    

def create_matrix_specific_plots(df_results, df_details):
    """Create analysis charts for different matrices"""
    
    # Set plot style
    plt.style.use('seaborn-v0_8')
    
    # 1. Hit rate comparison for three matrices
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    fig.suptitle('Cache Performance Comparison for Matrices A, B, C in Matrix Multiplication', fontsize=16, fontweight='bold')
    
    # Create subplots for each matrix type
    matrix_types = ['A', 'B', 'C']
    colors = {'A': 'blue', 'B': 'red', 'C': 'green'}
    
    for idx, matrix_type in enumerate(matrix_types):
        df_type = df_results[df_results['matrix_type'] == matrix_type]
        
        # Subplot 1: Hit rate vs matrix size
        ax1 = axes[0, idx]
        for cache_size in df_type['cache_size'].unique()[:3]:  # Limit display to avoid overcrowding
            for block_size in df_type['block_size'].unique()[:2]:
                subset = df_type[(df_type['cache_size'] == cache_size) & 
                                (df_type['block_size'] == block_size)]
                if not subset.empty:
                    label = f"Cache={cache_size}B, Block={block_size}B"
                    subset.groupby('matrix_size')['hit_rate'].mean().plot(
                        ax=ax1, label=label, marker='o', color=colors[matrix_type], alpha=0.7)
        
        ax1.set_xlabel('Matrix Size')
        ax1.set_ylabel('Hit Rate')
        ax1.set_title(f'Matrix {matrix_type} - Hit Rate vs Matrix Size')
        ax1.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=8)
        ax1.grid(True, alpha=0.3)
        
        # Subplot 2: Spatial locality analysis
        ax2 = axes[1, idx]
        spatial_data = df_type.groupby('matrix_size')['spatial_locality'].mean()
        ax2.bar(spatial_data.index, spatial_data.values, 
               color=colors[matrix_type], alpha=0.7)
        ax2.set_xlabel('Matrix Size')
        ax2.set_ylabel('Spatial Locality')
        ax2.set_title(f'Matrix {matrix_type} - Spatial Locality')
        ax2.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('matrix_specific_analysis.png', dpi=300, bbox_inches='tight')
    
    # 2. Performance comparison heatmap for three matrices
    fig, axes = plt.subplots(1, 3, figsize=(15, 5))
    
    for idx, matrix_type in enumerate(matrix_types):
        df_type = df_results[df_results['matrix_type'] == matrix_type]
        
        # Create heatmap: cache size vs block size vs hit rate
        pivot_table = df_type.pivot_table(values='hit_rate', 
                                         index='cache_size', 
                                         columns='block_size', 
                                         aggfunc='mean')
        
        sns.heatmap(pivot_table, annot=True, fmt='.3f', 
                   cmap='YlOrRd', ax=axes[idx], cbar_kws={'label': 'Hit Rate'})
        axes[idx].set_title(f'Matrix {matrix_type} - Cache Configuration Heatmap')
        axes[idx].set_xlabel('Block Size (Bytes)')
        axes[idx].set_ylabel('Cache Size (Bytes)')
    
    plt.tight_layout()
    plt.savefig('matrix_heatmaps.png', dpi=300, bbox_inches='tight')
    
    # 3. Access pattern analysis (using detailed data)
    if not df_details.empty:
        analyze_access_patterns(df_details)
    
    plt.show()

def analyze_access_patterns(df_details):
    """Analyze detailed access patterns"""
    
    # Analyze access patterns by matrix type
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))
    
    # 3.1 Hit/miss distribution
    ax1 = axes[0, 0]
    hit_miss_by_matrix = df_details.groupby(['matrix_type', 'hit']).size().unstack()
    hit_miss_by_matrix.plot(kind='bar', ax=ax1, color=['red', 'green'])
    ax1.set_title('Hit/Miss Distribution by Matrix')
    ax1.set_ylabel('Access Count')
    ax1.legend(['Miss', 'Hit'])
    ax1.grid(True, alpha=0.3)
    
    # 3.2 Row access pattern analysis
    ax2 = axes[0, 1]
    for matrix_type in df_details['matrix_type'].unique():
        df_type = df_details[df_details['matrix_type'] == matrix_type]
        row_access_count = df_type['row'].value_counts().sort_index()
        ax2.plot(row_access_count.index, row_access_count.values, 
                label=f'Matrix {matrix_type}', marker='o')
    
    ax2.set_xlabel('Row Index')
    ax2.set_ylabel('Access Count')
    ax2.set_title('Row Access Patterns by Matrix')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    # 3.3 Column access pattern analysis
    ax3 = axes[1, 0]
    for matrix_type in df_details['matrix_type'].unique():
        df_type = df_details[df_details['matrix_type'] == matrix_type]
        col_access_count = df_type['col'].value_counts().sort_index()
        ax3.plot(col_access_count.index, col_access_count.values, 
                label=f'Matrix {matrix_type}', marker='s')
    
    ax3.set_xlabel('Column Index')
    ax3.set_ylabel('Access Count')
    ax3.set_title('Column Access Patterns by Matrix')
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 3.4 Time-series access pattern
    ax4 = axes[1, 1]
    sample_experiment = df_details['experiment_name'].iloc[0]
    df_sample = df_details[df_details['experiment_name'] == sample_experiment]
    
    for matrix_type in df_sample['matrix_type'].unique():
        df_type = df_sample[df_sample['matrix_type'] == matrix_type]
        # Sample to reduce data points
        if len(df_type) > 1000:
            df_type = df_type.iloc[::len(df_type)//1000]
        
        ax4.scatter(df_type['timestamp'], df_type['row'], 
                   label=f'Matrix {matrix_type}', alpha=0.6, s=10)
    
    ax4.set_xlabel('Timestamp')
    ax4.set_ylabel('Row Index')
    ax4.set_title('Time-Series Access Pattern (Example)')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('access_pattern_analysis.png', dpi=300, bbox_inches='tight')

def generate_detailed_analysis(df_results, df_details):
    """Generate detailed analysis report"""
    
    print("\n" + "="*60)
    print("Detailed Cache Performance Analysis Report")
    print("="*60)
    
    # Analyze by matrix type
    for matrix_type in ['A', 'B', 'C']:
        df_type = df_results[df_results['matrix_type'] == matrix_type]
        
        print(f"\n--- Matrix {matrix_type} Analysis ---")
        print(f"Average Hit Rate: {df_type['hit_rate'].mean():.4f}")
        print(f"Average Miss Rate: {df_type['miss_rate'].mean():.4f}")
        print(f"Average Spatial Locality: {df_type['spatial_locality'].mean():.4f}")
        
        # Best configuration
        best_config = df_type.loc[df_type['hit_rate'].idxmax()]
        print(f"Best Configuration: Cache={best_config['cache_size']}B, Block Size={best_config['block_size']}B")
        print(f"Best Hit Rate: {best_config['hit_rate']:.4f}")
    
    # Comparative analysis
    print("\n--- Matrix Comparison Analysis ---")
    matrix_comparison = df_results.groupby('matrix_type').agg({
        'hit_rate': 'mean',
        'spatial_locality': 'mean'
    }).round(4)
    
    print("Hit Rate Comparison:")
    print(matrix_comparison['hit_rate'])
    
    print("\nSpatial Locality Comparison:")
    print(matrix_comparison['spatial_locality'])
    
    # Performance difference analysis
    a_hit_rate = df_results[df_results['matrix_type'] == 'A']['hit_rate']
    b_hit_rate = df_results[df_results['matrix_type'] == 'B']['hit_rate']
    
    t_stat, p_value = stats.ttest_ind(a_hit_rate, b_hit_rate)
    print(f"\nMatrix A vs Matrix B Hit Rate T-Test: t={t_stat:.4f}, p={p_value:.4f}")
    
    if p_value < 0.05:
        print("Significant difference exists between Matrix A and Matrix B hit rates")
    else:
        print("No significant difference between Matrix A and Matrix B hit rates")
    
    # Configuration recommendations
    print("\n--- Configuration Recommendations ---")
    for size in df_results['matrix_size'].unique():
        best_configs = {}
        for matrix_type in ['A', 'B', 'C']:
            df_type = df_results[(df_results['matrix_type'] == matrix_type) & 
                               (df_results['matrix_size'] == size)]
            if not df_type.empty:
                best = df_type.loc[df_type['hit_rate'].idxmax()]
                best_configs[matrix_type] = best
        
        if best_configs:
            print(f"\nMatrix Size {size}:")
            for matrix_type, config in best_configs.items():
                print(f"  Matrix {matrix_type}: Cache={config['cache_size']}B, "
                      f"Block Size={config['block_size']}B, Hit Rate={config['hit_rate']:.4f}")

if __name__ == "__main__":
    analyze_matrix_specific_cache()